package com.glela.biz.impl;

import com.alibaba.fastjson.JSON;
import com.glela.biz.RedPacketBiz;
import com.glela.cache.redis.RedisKeys;
import com.glela.cache.redis.RedisUtil;
import com.glela.common.service.SMSService;
import com.glela.common.util.DateUtil;
import com.glela.common.util.DateUtils;
import com.glela.common.util.JsonUtil;
import com.glela.domain.dto.*;
import com.glela.domain.vo.*;
import com.glela.packet.enums.*;
import com.glela.packet.exception.RedPacketBizException;
import com.glela.packet.model.*;
import com.glela.packet.service.*;
import com.glela.packet.util.RedPacketUtil;
import com.glela.platform.model.BaseRestrictions;
import com.glela.platform.model.User;
import com.glela.platform.model.response.ResponseUser;
import com.glela.platform.service.BaseRestrictionsService;
import com.glela.platform.service.UserService;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.Assert;
import org.springframework.util.CollectionUtils;

import java.io.IOException;
import java.math.BigDecimal;
import java.text.MessageFormat;
import java.text.SimpleDateFormat;
import java.util.*;
import java.util.stream.Collectors;
import java.util.stream.IntStream;

@Service("redPacketBiz")
public class RedPacketBizImpl implements RedPacketBiz {

    private static final Logger logger = LoggerFactory.getLogger(RedPacketBizImpl.class);

    @Autowired
    @Qualifier(value = "redPacketRecordService")
    private RedPacketRecordService redPacketRecordService;
    @Autowired
    @Qualifier(value = "redPacketRecordOmtRlService")
    private RedPacketRecordOmtRlService redPacketRecordOmtRlService;
    @Autowired
    @Qualifier(value = "redPacketOmtService")
    private RedPacketOmtService redPacketOmtService;
    @Autowired
    @Qualifier(value = "redPacketService")
    private RedPacketService redPacketService;
    @Autowired
    @Qualifier(value = "redPacketOwnerService")
    private RedPacketOwnerService redPacketOwnerService;
    @Autowired
    @Qualifier(value = "redPacketShareHistService")
    private RedPacketShareHistService redPacketShareHistService;
    @Autowired
    @Qualifier(value = "userService")
    private UserService userService;
    @Autowired
    private BaseRestrictionsService baseRestrictionsService;
    // h5兔币分享链接前缀
    private static final String RED_PACKET_SHARE_PREFIX = "red_packet_share";
    // 图片前缀
    private static final String IMAGE_PREFIX = "qiniu.http.base";
    // 直播间发短信模板
    private static final String LIVE_ROOM_GIVE_REDPACKET = "live_room_give_redPacket_sms";

    @Autowired
    private RedisUtil redisUtil;
    @Autowired
    @Qualifier(value = "SMSService")
    private SMSService smsService;

    /***
     * 系统赠送
     * @param request
     * @return
     */
    @Override
    @Transactional(propagation = Propagation.REQUIRED, rollbackFor = {Exception.class,
            RuntimeException.class})
    public boolean systemGiveRedPacket(SystemGiveRedPacketRequest request)
            throws RedPacketBizException {

        logger.info("===method systemGiveRedPacket request={}", request);

        Assert.notNull(request, "传入参数不能为空");

        if (CollectionUtils.isEmpty(request.getUserIdList())) {
            throw new RedPacketBizException("赠送的用户ID集合不能为空!");
        }
        RedPacketRecord redPacketRecord = redPacketRecordService
                .getRedPacketRecordById(request.getRedPacketRecordId());

        if (redPacketRecord == null) {
            logger.error("==发行记录不存在。 id = {}", request.getRedPacketRecordId());
            throw RedPacketBizException.RED_PACKET_RECORD_NOT_EXIST;
        }
        // 不属于启用状态
        if (redPacketRecord.getEnableFlag() != 1) {
            logger.error("==发行记录不属于启用状态。 id = {}", request.getRedPacketRecordId());
            throw RedPacketBizException.RED_PACKET_RECORD_IS_NOT_ENABLE;
        }
        // 已被删除
        if (redPacketRecord.getDeleteFlag()) {
            logger.error("==发行记录已被删除。 id = {}", request.getRedPacketRecordId());
            throw RedPacketBizException.RED_PACKET_RECORD_IS_DELETE;
        }
        // 判断当前时间是否在发行时间范围
        if (redPacketRecord.getStartTime().getTime() > System.currentTimeMillis()
                || redPacketRecord.getEndTime().getTime() < System.currentTimeMillis()) {
            logger.error("==当前时间不是在发行时间范围。 id = {}", request.getRedPacketRecordId());
            throw RedPacketBizException.RED_PACKET_RECORD_TIME_IS_INVALID;
        }
        // 用户列表长度
        int userSize =
                CollectionUtils.isEmpty(request.getUserIdList()) ? 0 : request.getUserIdList().size();
        if (userSize == 0) {
            logger.error("==用户列表长度为0。id = {}", request.getRedPacketRecordId());
            throw RedPacketBizException.PARAM_ERROR;
        }
        // 最大用户个数
        int maxLimitSize = 100;

        logger.info("==============本次userSize == {} -------------------------------", userSize);

        if (userSize > maxLimitSize) {
            logger.error("==用户列表长度为{},已大于最大限制个{}。id = {}", userSize, maxLimitSize,
                    request.getRedPacketRecordId());
            throw new RedPacketBizException(
                    "单赠送用户列表长度不能大于最大长度：" + maxLimitSize + ",当前请求用户长度：" + userSize);
        }
        // 用户id列表
        List<Integer> userIdList = request.getUserIdList();

        // 查询发行记录关联表
        List<RedPacketRecordOmtRl> recordOmtRls = redPacketRecordOmtRlService
                .listByRedPacketRecordId(redPacketRecord.getId());
        if (CollectionUtils.isEmpty(recordOmtRls)) {
            throw new RedPacketBizException("兔币发行记录没有关联兔币模板");
        }

        List<Integer> omtIdList = recordOmtRls.stream().filter(rl -> {
            if (rl.getRemainCount() < userSize) {
                throw new RedPacketBizException("兔币发行记录的兔币数量不够。rlId = " + rl.getId());
            }
            if (rl.getSendNums() <= 0) {
                throw new RedPacketBizException("兔币发行记录的兔币发送数量不能小于0。rlId = " + rl.getId());
            }
            return true;
        }).map(RedPacketRecordOmtRl::getRedPacketOmtId).collect(Collectors.toList());

        if (CollectionUtils.isEmpty(omtIdList)) {
            throw new RedPacketBizException("没有找到有效的兔币模板。redPacketRecordId = " + redPacketRecord.getId());
        }
        // 查询兔币模块列表
        List<RedPacketOmt> redPacketOmtList = redPacketOmtService.listByIds(omtIdList);

        if (CollectionUtils.isEmpty(redPacketOmtList)) {
            throw new RedPacketBizException("兔币发行记录没有关联任何兔币模板");
        }

        Map<Integer, RedPacketOmt> redPacketOmtMap = redPacketOmtList.stream().filter(redPacketOmt -> {
            if (redPacketOmt.getRedPacketAgingType().intValue() == 0) {
                if (redPacketOmt.getRedPacketEndTime().getTime() < System.currentTimeMillis()) {
                    throw new RedPacketBizException("兔币模板有效时间范围无效");
                }
            }
            return true;
        }).collect(Collectors.toMap(RedPacketOmt::getId, omt -> omt));

        recordOmtRls.stream().forEach(rl -> {

            RedPacketOmt redPacketOmt = redPacketOmtMap.get(rl.getRedPacketOmtId());
            // 设置红包的标题为活动的标题
            redPacketOmt.setRedPacketTitle(redPacketRecord.getTitle());
            redPacketOmt.setRedPacketSubtitle(redPacketRecord.getTitle());

            if (redPacketOmt != null) {
                IntStream.range(0, rl.getSendNums()).forEach(i -> {
                    // 生成userSize个兔币
                    List<RedPacket> redPacketList = this.generateRedPacket(userSize, userIdList, redPacketOmt,
                            RedPacketUtil.generateRedPacketCode(
                                    RedPacketEventTypeEnum.getByType(redPacketRecord.getEventType()).getPrefix())
                                    + "-" + rl.getRedPacketRecordId() + "-" + rl.getRedPacketOmtId());

                    //  更新兔币剩余数量
                    RedPacketRecordOmtRl updateOmtRl = new RedPacketRecordOmtRl();
                    updateOmtRl.setId(rl.getId());
                    updateOmtRl.setRemainCount(userSize);

                    boolean updateFlag = redPacketRecordOmtRlService.updateRedPacketRemainCount(updateOmtRl);

                    if (!updateFlag) {
                        throw new RedPacketBizException("兔币发行记录的剩余兔币数量不够");
                    }
                    //  批量插入兔币
                    redPacketService.batchSaveRedPacket(redPacketList);

                    List<RedPacketOwner> ownerList = this.generateOwnerList(userIdList, redPacketList);
                    //  批量将兔币关联用户
                    redPacketOwnerService.batchSaveRedPacketOwner(ownerList);
                });
            }
        });

        userIdList.stream().forEach(userId -> redisUtil.delKeysLike(RedisKeys.RED_PACKET + userId));

        return true;
    }

    /****
     * 分享兔币
     * @param request
     * @return
     */
    @Override
    @Transactional(propagation = Propagation.REQUIRED, rollbackFor = {Exception.class,
            RuntimeException.class})
    public ShareRedPacketVo shareRedPacket(ShareRedPacketRequest request)
            throws RedPacketBizException {

        logger.info("===method shareRedPacket request={}", request);

        Assert.notNull(request, "传入参数不能为空");

        ShareRedPacketVo shareRedPacketVo = new ShareRedPacketVo();

        RedPacketOwner redPacketOwner = redPacketOwnerService
                .getRedPacketOwnerById(request.getRedPacketOwnerId());

        if (redPacketOwner == null) {
            throw new RedPacketBizException("您所分享的兔币不存在");
        }

        if (RedPacketShareTypeEnum.getByType(request.getType()) == null) {
            throw new RedPacketBizException("分享类型错误");
        }

        if (redPacketOwner.getOwnUserId().intValue() != request.getShareUserId()) {
            logger.error("==当前分享者不是分享自己的兔币,ownUserId={},shareUserId={}", redPacketOwner.getOwnUserId(),
                    request.getShareUserId());
            throw new RedPacketBizException("非法分享");
        }

        if (redPacketOwner.getOwnStatus() == 0) {
            logger.error("==当前兔币拥有者的拥有状态不是当前拥有,而是曾经拥有");
            throw new RedPacketBizException("非法分享");
        }

        if (redPacketOwner.getEffectiveStartTime().getTime() > System.currentTimeMillis()) {
            logger.error("==这个是个未来红包,当前不能分享");
            String message =
                    "请在 " + DateUtils
                            .dateFormat(redPacketOwner.getEffectiveStartTime(), "yyyy-MM-dd HH:mm:ss") + " ~ "
                            + DateUtils.dateFormat(redPacketOwner.getEffectiveEndTime(), "yyyy-MM-dd HH:mm:ss")
                            + " 期间进行分享。";
            throw new RedPacketBizException(message);
        }

        if (redPacketOwner.getRedPacketStatus() == RedPacketStatusEnum.OVERDUE.getStatus()) {
            logger.error("==兔币已过期");
            throw new RedPacketBizException("兔币已过期");
        }

        if (redPacketOwner.getEffectiveEndTime().getTime() < System.currentTimeMillis()) {
            logger.error("==兔币使用时间已过期");
            throw new RedPacketBizException("兔币已过期");
        }
        // 查询是否有分享记录
        if (redPacketOwner.getRedPacketShareHistId() > 0) {
            RedPacketShareHist redPacketShareHist = redPacketShareHistService
                    .getRedPacketShareHistById(redPacketOwner.getRedPacketShareHistId());

            if (redPacketShareHist == null) {
                logger.error("==兔币分享记录不存在。 redPacketShareHistId = {}",
                        redPacketOwner.getRedPacketShareHistId());
                throw new RedPacketBizException("非法分享");
            }

            if (redPacketShareHist.getStatus() != RedPacketShareHistStatusEnum.NOT_RECEIVE.getStatus()) {
                logger.error("==兔币分享记录不在待领取。 redPacketShareHistId = {}",
                        redPacketOwner.getRedPacketShareHistId());
                throw new RedPacketBizException("兔币已被领取");
            }
            BaseRestrictions baseRestrictions = baseRestrictionsService
                    .getBaseRestrictionsForCache(RED_PACKET_SHARE_PREFIX);

            redisUtil
                    .set(RedisKeys.RED_PACKET_SHARE_KEY + redPacketShareHist.getShareUrl(),
                            redPacketOwner.getRedPacketShareHistId() + "", 2 * 24 * 60 * 60);

            shareRedPacketVo.setShareUrl(
                    (baseRestrictions == null ? "" : baseRestrictions.getName()) + "shareKey="
                            + redPacketShareHist.getShareUrl() + "&talentId=" + request.getShareUserId());

            ShareRedPacketInfoVo infoVo = this.getShareRedPacketInfoVo();
            if (infoVo != null) {
                shareRedPacketVo.setActiveDesc(infoVo.getActiveDesc());
                shareRedPacketVo.setImagePic(infoVo.getImagePic());
                shareRedPacketVo.setStoreUserName(infoVo.getStoreUserName());
            }

            return shareRedPacketVo;
        }
        if (!redPacketOwner.getAllowShare()) {
            throw new RedPacketBizException("这是一个限时分享兔币，不能分享了哦");
        }

        if (redPacketOwner.getRedPacketShareStatus() != RedPacketShareStatusEnum.NOT_SHARE
                .getStatus()) {
            throw new RedPacketBizException("该兔币已被分享");
        }

        ResponseUser user = userService.selectUserRoleById(request.getShareUserId());

        if (user.isNotStoreLevel()) {
            throw new RedPacketBizException("小白用户不能分享兔币");
        }

        boolean acquireLock =
                redisUtil
                        .setnx(RedisKeys.RED_PACKET_SHARE_LOCK + request.getRedPacketOwnerId(), "1", 1 * 60)
                        > 0;
        // 没有获取的锁 重新
        if (!acquireLock) {
            try {
                Thread.sleep(new Random().nextInt(500) + 500);
                shareRedPacket(request);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
        try {
            // 兔币分享表新增一条数据
            RedPacketShareHist redPacketShareHist = new RedPacketShareHist();
            redPacketShareHist.setShareUserId(request.getShareUserId());
            redPacketShareHist.setRedPacketId(redPacketOwner.getRedPacketId());
            redPacketShareHist.setShareLevel(1);
            redPacketShareHist.setShareTime(new Date());
            redPacketShareHist.setUpdateTime(new Date());
            redPacketShareHist.setShareType((short) request.getType());
            redPacketShareHist.setStatus(RedPacketShareHistStatusEnum.NOT_RECEIVE.getStatus());

            redPacketShareHistService.saveRedPacketShareHist(redPacketShareHist);

            RedPacketShareHist updateHist = new RedPacketShareHist();
            updateHist.setId(redPacketShareHist.getId());
            updateHist.setShareUrl(
                    RedPacketUtil.generateShareKey(request.getShareUserId(), redPacketShareHist.getId()));
            redPacketShareHistService.updateRedPacketShareHist(updateHist);

            RedPacketOwner updateOwner = new RedPacketOwner();
            updateOwner.setId(redPacketOwner.getId());
            updateOwner.setRedPacketShareHistId(redPacketShareHist.getId());
            updateOwner.setRedPacketStatus(RedPacketStatusEnum.USED.getStatus());
            updateOwner.setRedPacketShareStatus(RedPacketShareStatusEnum.SHARED.getStatus());
            updateOwner.setUsedTime(new Date());
            // 兔币剩余使用有效时间
            long remainTime = redPacketOwner.getEffectiveEndTime().getTime() - System.currentTimeMillis();
            // 24小时
            long oneDay = 3600000 * 24L;
            // 兔币剩余使用有效期≤24h，则分享后，兔币领取有效期为：分享开始——原兔币到期时间
            if (remainTime <= oneDay) {
                updateOwner.setShareFailureTime(redPacketOwner.getEffectiveEndTime());
            } else {
                // 兔币剩余使用有效期＞24h，则分享后，兔币领取有效期为：分享后24h
                Calendar calendar = Calendar.getInstance();
                calendar.setTime(new Date());
                calendar.add(Calendar.HOUR_OF_DAY, 24);
                updateOwner.setShareFailureTime(calendar.getTime());
            }
            // 更新兔币拥有者的兔币状态，分享状态，兔币领取失效时间
            redPacketOwnerService.updateRedPacketOwner(updateOwner);

            String shareKey = RedisKeys.RED_PACKET_SHARE_KEY + updateHist.getShareUrl();
            // 将分享的Key放入redis 缓存24h
            int result = redisUtil.setnx(shareKey, redPacketShareHist.getId() + "", 2 * 24 * 60 * 60);
            if (result == 0) {
                throw new RedPacketBizException("该兔币已被分享");
            }
            BaseRestrictions baseRestrictions = baseRestrictionsService
                    .getBaseRestrictionsForCache(RED_PACKET_SHARE_PREFIX);

            shareRedPacketVo.setShareUrl(
                    (baseRestrictions == null ? "" : baseRestrictions.getName()) + "shareKey="
                            + updateHist.getShareUrl() + "&talentId=" + request.getShareUserId());

            ShareRedPacketInfoVo infoVo = this.getShareRedPacketInfoVo();
            if (infoVo != null) {
                shareRedPacketVo.setActiveDesc(infoVo.getActiveDesc());
                shareRedPacketVo.setImagePic(infoVo.getImagePic());
                shareRedPacketVo.setStoreUserName(infoVo.getStoreUserName());
            }

            //分享成功后把该用户在redis中相关兔币信息 清掉   领取的人 也要删掉
            redisUtil.delKeysLike(RedisKeys.RED_PACKET + request.getShareUserId() + "*");
            redisUtil.delKeysLike(RedisKeys.RED_PACKET_SHARE + request.getShareUserId() + "*");

            redisUtil.del(RedisKeys.RED_PACKET_SHARE_LOCK + request.getRedPacketOwnerId());

        } catch (RedPacketBizException e) {
            e.printStackTrace();
            logger.error("----分享兔币异常---", e);
            throw e;
        } catch (Exception e) {
            e.printStackTrace();
            logger.error("----分享兔币异常---", e);
            throw new RedPacketBizException("分享兔币异常");
        } finally {
            // 删除锁
            redisUtil.del(RedisKeys.RED_PACKET_SHARE_LOCK + request.getRedPacketOwnerId());
        }

        return shareRedPacketVo;
    }


    private ShareRedPacketInfoVo getShareRedPacketInfoVo() {
        BaseRestrictions baseRestrictions = baseRestrictionsService
                .getBaseRestrictionsForCache("red_packet_share_info");
        if (baseRestrictions != null && StringUtils.isNotBlank(baseRestrictions.getName())) {
            ShareRedPacketInfoVo infoVo = JSON
                    .parseObject(baseRestrictions.getName(), ShareRedPacketInfoVo.class);
            if (infoVo != null) {
                return infoVo;
            }
        }
        return null;
    }

    /****
     * 获取图片全路径
     * @param imageUrl
     * @return
     */
    private String getImageAllPath(String imageUrl) {
        String fullPath = "";
        if (StringUtils.isBlank(imageUrl)) {
            return fullPath;
        }
        if (imageUrl.contains("http") || imageUrl.contains("HTTP")) {
            return imageUrl;
        }
        BaseRestrictions baseRestrictions = baseRestrictionsService
                .getBaseRestrictionsForCache(IMAGE_PREFIX);
        if (baseRestrictions != null && StringUtils.isNotBlank(baseRestrictions.getName())) {
            fullPath = baseRestrictions.getName() + imageUrl;
        }
        return fullPath;
    }

    /****
     * 领取兔币
     * @param request
     * @return
     */
    @Override
    @Transactional(propagation = Propagation.REQUIRED, rollbackFor = {Exception.class,
            RuntimeException.class})
    public GetRedPacketByShareKeyVo receiveRedPacket(ReceiveRedPacketRequest request)
            throws RedPacketBizException {

        logger.info("===method receiveRedPacket request={}", request);

        Assert.notNull(request, "传入参数不能为空");

        GetRedPacketByShareKeyVo vo = new GetRedPacketByShareKeyVo();
        vo.setStatus(0); // 未领取

        if (StringUtils.isBlank(request.getShareKey())) {
            throw new RedPacketBizException("参数错误");
        }

        // 是否已过期
        String jsonValue = redisUtil
                .get(RedisKeys.RED_PACKET_SHARE_STATUS + "overdue_" + request.getShareKey());

        if (StringUtils.isNotBlank(jsonValue)) {
            return JSON.parseObject(jsonValue, GetRedPacketByShareKeyVo.class);
        }

        // 是否是自己分享
        jsonValue = redisUtil
                .get(RedisKeys.RED_PACKET_SHARE_STATUS + "myself_" + request.getShareKey() + "_" + request
                        .getReceiveUserId());

        if (StringUtils.isNotBlank(jsonValue)) {
            return JSON.parseObject(jsonValue, GetRedPacketByShareKeyVo.class);
        }

        // 是否是自己领取
        jsonValue = redisUtil.get(
                RedisKeys.RED_PACKET_SHARE_STATUS + "receive_" + request.getShareKey() + "_" + request
                        .getReceiveUserId());

        if (StringUtils.isNotBlank(jsonValue)) {
            return JSON.parseObject(jsonValue, GetRedPacketByShareKeyVo.class);
        }

        // 是否已失效
        jsonValue = redisUtil
                .get(RedisKeys.RED_PACKET_SHARE_STATUS + "invalid_" + request.getShareKey());

        if (StringUtils.isNotBlank(jsonValue)) {
            return JSON.parseObject(jsonValue, GetRedPacketByShareKeyVo.class);
        }

        String shareKey = RedisKeys.RED_PACKET_SHARE_KEY + request.getShareKey();
        String shareKeyValue = redisUtil.get(shareKey);

        RedPacketShareHist redPacketShareHist = null;

        if (StringUtils.isNotBlank(shareKeyValue)) {
            redPacketShareHist = redPacketShareHistService
                    .getRedPacketShareHistById(Integer.valueOf(shareKeyValue));
        } else {
            redPacketShareHist = redPacketShareHistService
                    .getRedPacketShareHisByShareUrl(request.getShareKey());
        }

        if (redPacketShareHist == null) {
            throw new RedPacketBizException("兔币分享不存在");
        }

        User shareUser = userService.getUserById(Long.valueOf(redPacketShareHist.getShareUserId()));
        if (shareUser == null) {
            throw new RedPacketBizException("兔币分享人信息不存在");
        }
        vo.setShareUserName(shareUser.getNickName());
        vo.setShareUserPic(this.getImageAllPath(shareUser.getPicture()));

        RedPacket redPacket = redPacketService.getRedPacketById(redPacketShareHist.getRedPacketId());
        if (redPacket == null) {
            throw new RedPacketBizException("兔币记录不存在");
        }

        RedPacketOwner redPacketOwner = redPacketOwnerService
                .getByRedPacketShareHistId(redPacketShareHist.getId());

        if (redPacketOwner == null) {
            throw new RedPacketBizException("兔币拥有记录不存在");
        }

        User user = userService.getUserById((long) request.getReceiveUserId());
        if (user == null) {
            throw new RedPacketBizException("领取人用户信息不存在");
        }

        // 判断 兔币使用时间是否已过期 或者 兔币领取时间是否已失效
        if ((redPacketOwner.getEffectiveEndTime().getTime() < System.currentTimeMillis())
                || (redPacketOwner.getShareFailureTime() != null &&
                redPacketOwner.getShareFailureTime().getTime() < System.currentTimeMillis())) {
            vo.setStatus(4);
        }
        vo.setLastValidTime(
                new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(redPacketOwner.getEffectiveEndTime()));
        vo.setShareUserName(shareUser.getNickName());
        vo.setShareUserPic(this.getImageAllPath(shareUser.getPicture()));
        vo.setAmount(BigDecimal.valueOf(redPacket.getAmount().longValue()).divide(BigDecimal.valueOf(100)).toString());

        // 已过期
        if (vo.getStatus() == 4) {
            redisUtil
                    .set(RedisKeys.RED_PACKET_SHARE_STATUS + "overdue_" + request.getShareKey(),
                            JSON.toJSONString(vo),
                            2 * 24 * 60 * 60);
            return vo;
        }

        if (redPacketShareHist.getShareUserId().intValue() == request.getReceiveUserId()) {
            // 不能领取自己的兔币
            vo.setStatus(10);
        } else {
            if (redPacketShareHist.getStatus() == RedPacketShareHistStatusEnum.RECEIVED.getStatus()) {
                // 自己已领取
                if (redPacketShareHist.getReceiveUserId().intValue() == request.getReceiveUserId()) {
                    vo.setStatus(2);
                } else {
                    // 失效（他人领取）
                    vo.setStatus(1);
                }
            } else if (redPacketShareHist.getStatus() != RedPacketShareHistStatusEnum.NOT_RECEIVE
                    .getStatus()) {
                // 失效（他人领取）
                vo.setStatus(1);
            }
        }

        if (vo.getStatus() == 10) {
            redisUtil
                    .set(RedisKeys.RED_PACKET_SHARE_STATUS + "myself_" + request.getShareKey() + "_" + request
                                    .getReceiveUserId()
                            , JSON.toJSONString(vo), 2 * 24 * 60 * 60);
            return vo;
        }
        // 自己领取
        if (vo.getStatus() == 2) {
            redisUtil
                    .set(
                            RedisKeys.RED_PACKET_SHARE_STATUS + "receive_" + request.getShareKey() + "_" + request
                                    .getReceiveUserId()
                            , JSON.toJSONString(vo), 2 * 60);
            return vo;
        }

        // 已失效
        if (vo.getStatus() == 1) {
            redisUtil.set(RedisKeys.RED_PACKET_SHARE_STATUS + "invalid_" + request.getShareKey(),
                    JSON.toJSONString(vo), 2 * 60);
            return vo;
        }

        boolean acquireLock =
                redisUtil.setnx(RedisKeys.RED_PACKET_RECEIVE_LOCK + request.getShareKey(), "1", 60) > 0;
        // 没有获取锁 重新获取锁
        if (!acquireLock) {
            try {
                Thread.sleep(new Random().nextInt(500) + 500);
                receiveRedPacket(request);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }

        try {
            // 更新当前拥有者的分享记录 信息 状态 为 已领取 更新领取者相关信息
            RedPacketShareHist updateShareHist = new RedPacketShareHist();
            updateShareHist.setId(redPacketShareHist.getId());
            updateShareHist.setReceiveTime(new Date());
            updateShareHist.setReceiveUserId(request.getReceiveUserId());
            updateShareHist.setReceiveUserNickname(user.getNickName());
            updateShareHist.setStatus(RedPacketShareHistStatusEnum.RECEIVED.getStatus());

            redPacketShareHistService.updateRedPacketShareHist(updateShareHist);

            RedPacketOwner newRedPacketOwner = new RedPacketOwner();
            newRedPacketOwner.setTitle("小铺店主赠送的兔币");
            newRedPacketOwner.setGiftType(RedPacketGiftTypeEnum.SHARE_RECEIVE.getType());
            newRedPacketOwner.setOwnUserId(request.getReceiveUserId());
            newRedPacketOwner.setOwnTime(new Date());
            newRedPacketOwner.setRedPacketId(redPacketOwner.getRedPacketId());
            newRedPacketOwner.setRedPacketShareHistId(0);
            newRedPacketOwner.setAllowShare(true);
            newRedPacketOwner.setSendUserId(redPacketShareHist.getShareUserId());
            newRedPacketOwner.setLastOwnerId(0);
            newRedPacketOwner.setOwnStatus(RedPacketOwnStatusEnum.CURRENT.getStatus());
            newRedPacketOwner.setRedPacketShareStatus(RedPacketShareStatusEnum.NOT_SHARE.getStatus());
            newRedPacketOwner.setRedPacketStatus(RedPacketStatusEnum.NOT_USE.getStatus());

            // 限时分享
            if (redPacketShareHist.getShareType() == RedPacketShareTypeEnum.LIMIT_TYPE.getType()) {
                newRedPacketOwner.setAllowShare(false); // 限时兔币不再进行分享
                newRedPacketOwner.setLastOwnerId(redPacketOwner.getId()); // 关联上一个拥有者记录id
                //newRedPacketOwner.setShareFailureTime(redPacketOwner.getShareFailureTime()); // 新的分享失效时间不变
                // 兔币剩余使用有效时间
                long remainTime = redPacket.getEndTime().getTime() - System.currentTimeMillis();
                // 24小时
                long oneDay = 3600000 * 24L;
                //  如领取人领取后，兔币剩余使用有效期≤24h，则领取后，领取者的账户兔币使用有效期为：领取时间——原兔币到期时间
                if (remainTime <= oneDay) {
                    newRedPacketOwner.setEffectiveStartTime(new Date());
                    newRedPacketOwner.setEffectiveEndTime(redPacket.getEndTime());
                } else {
                    // 兔币剩余使用有效期＞24h，则领取后，领取者的账户兔币使用有效期为：领取后的24h
                    Calendar calendar = Calendar.getInstance();
                    calendar.setTime(new Date());
                    calendar.add(Calendar.HOUR_OF_DAY, 24);
                    newRedPacketOwner.setEffectiveStartTime(new Date());
                    newRedPacketOwner.setEffectiveEndTime(calendar.getTime());
                }
            } else {
                // 永久分享 继承兔币的使用有效时间
                newRedPacketOwner.setEffectiveStartTime(redPacket.getStartTime());
                newRedPacketOwner.setEffectiveEndTime(redPacket.getEndTime());
                newRedPacketOwner.setAllowShare(true);
            }
            //  新增一条拥有者的记录
            redPacketOwnerService.saveRedPacketOwner(newRedPacketOwner);

            if (redPacketShareHist.getShareType() == RedPacketShareTypeEnum.FOREVER_TYPE.getType()) {
                // 更新当前拥有者的拥有状态 拥有 1 -> 曾经 0
                RedPacketOwner updateOwner = new RedPacketOwner();
                updateOwner.setId(redPacketOwner.getId());
                updateOwner.setOwnStatus(RedPacketOwnStatusEnum.IN_THE_PAST.getStatus());
                redPacketOwnerService.updateRedPacketOwner(updateOwner);
            }

            vo.setStatus(8); // 自己领取成功
            vo.setAmount(BigDecimal.valueOf(redPacket.getAmount().longValue()).divide(BigDecimal.valueOf(100)).toString());
            vo.setLastValidTime(new SimpleDateFormat("yyyy-MM-dd HH:mm:ss")
                    .format(newRedPacketOwner.getEffectiveEndTime()));
            redisUtil.delKeysLike(RedisKeys.RED_PACKET + redPacketOwner.getOwnUserId() + "*");
            redisUtil.delKeysLike(RedisKeys.RED_PACKET_SHARE + redPacketOwner.getOwnUserId() + "*");
            redisUtil.delKeysLike(RedisKeys.RED_PACKET + request.getReceiveUserId() + "*");
            // 删除锁
            redisUtil.del(RedisKeys.RED_PACKET_RECEIVE_LOCK + request.getShareKey());

        } catch (RedPacketBizException e) {
            e.printStackTrace();
            logger.error("----领取红包异常---", e);
            throw e;
        } catch (Exception e) {
            e.printStackTrace();
            logger.error("----领取红包异常---", e);
            throw new RedPacketBizException("领取红包异常");
        } finally {
            // 删除锁
            redisUtil.del(RedisKeys.RED_PACKET_RECEIVE_LOCK + request.getShareKey());
        }

        return vo;
    }

    /***
     * 消费兔币
     * @param request
     * @return
     */
    @Override
    @Transactional(propagation = Propagation.REQUIRED, rollbackFor = {Exception.class,
            RuntimeException.class})
    public boolean consumeRedPacket(ConsumeRedPacketRequest request) throws RedPacketBizException {

        logger.info("===method receiveRedPacket request={}", request);

        Assert.notNull(request, "传入参数不能为空");

        RedPacketOwner redPacketOwner = redPacketOwnerService
                .getRedPacketOwnerById(request.getRedPacketOwnerId());

        if (redPacketOwner == null) {
            throw new RedPacketBizException("兔币不存在");
        }
        // 下单未支付或未支付
        if (request.getConsumeType() == 0 || request.getConsumeType() == 1) {

            if (redPacketOwner.getRedPacketStatus() == RedPacketStatusEnum.NOT_USE.getStatus()) {

                if (redPacketOwner.getOwnUserId() != request.getUserId()) {
                    logger.info("==当前兔币拥有者跟兔币使用者不一样。ownUserId = {},userId = {}", redPacketOwner.getOwnUserId(),
                            request.getUserId());
                    throw new RedPacketBizException("兔币无效");
                }
                // 判断兔币使用有效期
                if (redPacketOwner.getEffectiveEndTime().getTime() < System.currentTimeMillis()) {
                    throw new RedPacketBizException("该兔币已过期");
                }
                // 更新拥有者的使用状态
                RedPacketOwner updateOwner = new RedPacketOwner();
                updateOwner.setId(redPacketOwner.getId());
                updateOwner.setUsedTime(new Date());
                updateOwner.setRedPacketStatus(RedPacketStatusEnum.USED.getStatus());
                updateOwner.setRedPacketShareStatus(RedPacketShareHistStatusEnum.CONSUMED.getStatus());

                redPacketOwnerService.updateRedPacketOwner(updateOwner);

                redisUtil.delKeysLike(RedisKeys.RED_PACKET + redPacketOwner.getOwnUserId() + "*");
            }
        }
        if (request.getConsumeType() == 1) {
            // 下单支付
            // 更新兔币状态为已使用
            RedPacket updateRedPacket = new RedPacket();
            updateRedPacket.setId(redPacketOwner.getRedPacketId());
            updateRedPacket.setStatus(RedPacketStatusEnum.USED.getStatus());
            updateRedPacket.setUpdateTime(new Date());
            updateRedPacket.setUsetime(new Date());

            redPacketService.updateRedPacket(updateRedPacket);

            // 如果当前拥有者还有上一级 则更新上一级分享记录信息 更新兔币状态 为已使用
            if (redPacketOwner.getLastOwnerId() > 0) {
                RedPacketOwner lastOwner = redPacketOwnerService
                        .getRedPacketOwnerById(redPacketOwner.getLastOwnerId());
                if (lastOwner != null) {

                    RedPacketOwner updateLastOwner = new RedPacketOwner();
                    updateLastOwner.setId(lastOwner.getId());
                    updateLastOwner.setOwnStatus(RedPacketOwnStatusEnum.IN_THE_PAST.getStatus());
                    updateLastOwner.setUsedTime(new Date());

                    redPacketOwnerService.updateRedPacketOwner(updateLastOwner);

                    if (lastOwner.getRedPacketShareHistId() > 0) {
                        RedPacketShareHist redPacketShareHist = redPacketShareHistService
                                .getRedPacketShareHistById(lastOwner.getRedPacketShareHistId());
                        if (redPacketShareHist != null) {
                            RedPacketShareHist updateShareHist = new RedPacketShareHist();
                            updateShareHist.setId(redPacketShareHist.getId());
                            updateShareHist.setUpdateTime(new Date());
                            updateShareHist.setStatus(RedPacketShareHistStatusEnum.USED.getStatus());
                            redPacketShareHistService.updateRedPacketShareHist(updateShareHist);
                        }
                    }
                }
                redisUtil.delKeysLike(RedisKeys.RED_PACKET + lastOwner.getOwnUserId() + "*");
                redisUtil.delKeysLike(RedisKeys.RED_PACKET_SHARE + lastOwner.getOwnUserId() + "*");
            }
        }

        return true;
    }

    /****
     * 退回兔币
     * @param request
     * @return
     */
    @Override
    @Transactional(propagation = Propagation.REQUIRED, rollbackFor = {Exception.class,
            RuntimeException.class})
    public boolean backRedPacket(BackRedPacketRequest request) throws RedPacketBizException {

        logger.info("===method backRedPacket request={}", request);

        Assert.notNull(request, "传入参数不能为空");

        RedPacketOwner redPacketOwner = redPacketOwnerService
                .getRedPacketOwnerById(request.getRedPacketOwnerId());

        if (redPacketOwner == null) {
            logger.info("==兔币不存在");
            return false;
        }
        RedPacket redPacket = redPacketService.getRedPacketById(redPacketOwner.getRedPacketId());

        if (redPacket == null) {
            logger.info("==兔币不存在");
            return false;
        }

        RedPacketOwner updateOwner = new RedPacketOwner();
        updateOwner.setId(redPacketOwner.getId());
        updateOwner.setReturnTime(new Date());
        // 兔币使用时间未失效
        if (redPacketOwner.getEffectiveEndTime().getTime() > System.currentTimeMillis()) {
            updateOwner.setRedPacketStatus(RedPacketStatusEnum.NOT_USE.getStatus());
            updateOwner.setRedPacketShareStatus(RedPacketShareStatusEnum.NOT_SHARE.getStatus());
            updateOwner.setUsedTime(null);
            redPacketOwnerService.updateRedPacketOwnerUseTime(updateOwner);
        } else {
            updateOwner.setUsedTime(null);
            updateOwner.setRedPacketStatus(RedPacketStatusEnum.OVERDUE.getStatus());
            updateOwner.setRedPacketShareStatus(RedPacketShareStatusEnum.NOT_SHARE.getStatus());
            redPacketOwnerService.updateRedPacketOwnerUseTime(updateOwner);
        }

        if (redPacketOwner.getLastOwnerId() > 0) {
            RedPacketOwner lastOwner = redPacketOwnerService
                    .getRedPacketOwnerById(redPacketOwner.getLastOwnerId());
            if (lastOwner != null && lastOwner.getRedPacketShareHistId() > 0) {
                RedPacketOwner updateLastOwner = new RedPacketOwner();
                updateLastOwner.setId(lastOwner.getId());
                updateLastOwner.setOwnStatus(RedPacketOwnStatusEnum.CURRENT.getStatus());
                updateOwner.setReturnTime(new Date());
                redPacketOwnerService.updateRedPacketOwner(updateLastOwner);
            }
        }

        redisUtil.delKeysLike(RedisKeys.RED_PACKET + redPacketOwner.getOwnUserId() + "*");

        //分两种情况 1、下单未支付取消返还  2、下单已支付取消返还
        // 1、下单未支付取消返还
        if (RedPacketBackTypeEnum.NOT_PAY.getType() == request.getBackType()) {
            // 存在在上级 说明是限时兔币
            if (redPacketOwner.getLastOwnerId() > 0) {
                // 若退还时已过有效期，领取者兔币将失效
                if (redPacketOwner.getEffectiveEndTime().getTime() < System.currentTimeMillis()) {

                    RedPacketOwner lastOwner = redPacketOwnerService
                            .getRedPacketOwnerById(redPacketOwner.getLastOwnerId());

                    if (lastOwner != null && lastOwner.getRedPacketShareHistId() > 0) {
                        RedPacketShareHist shareHist = redPacketShareHistService
                                .getRedPacketShareHistById(lastOwner.getRedPacketShareHistId());
                        if (shareHist != null) {
                            if (lastOwner.getRedPacketStatus() != RedPacketStatusEnum.OVERDUE.getStatus()) {

                                RedPacketOwner updateLastOwner = new RedPacketOwner();
                                updateLastOwner.setId(lastOwner.getId());
                                updateLastOwner.setOwnStatus(RedPacketOwnStatusEnum.IN_THE_PAST.getStatus());
                                updateOwner.setReturnTime(new Date());
                                redPacketOwnerService.updateRedPacketOwner(updateLastOwner);

                                RedPacketShareHist updateShareHist = new RedPacketShareHist();
                                updateShareHist.setId(shareHist.getId());
                                updateShareHist.setStatus(RedPacketShareHistStatusEnum.BACKED.getStatus());
                                updateShareHist.setReturnTime(new Date());
                                updateShareHist.setUpdateTime(new Date());
                                redPacketShareHistService.updateRedPacketShareHist(updateShareHist);

                                RedPacketOwner newOwner = new RedPacketOwner();
                                newOwner.setTitle("分享退回兔币");
                                newOwner.setOwnUserId(lastOwner.getOwnUserId());
                                newOwner.setRedPacketId(lastOwner.getRedPacketId());
                                newOwner.setRedPacketShareHistId(0);
                                newOwner.setLastOwnerId(0);
                                newOwner.setAllowShare(true);
                                newOwner.setOwnTime(new Date());
                                newOwner.setSendUserId(0);
                                newOwner.setOwnStatus(RedPacketOwnStatusEnum.CURRENT.getStatus());
                                newOwner.setGiftType(RedPacketGiftTypeEnum.SHARE_BACK.getType());
                                newOwner.setRedPacketShareStatus(RedPacketShareStatusEnum.NOT_SHARE.getStatus());

                                if (lastOwner.getEffectiveEndTime().getTime() > System.currentTimeMillis()) {
                                    newOwner.setRedPacketStatus(RedPacketStatusEnum.NOT_USE.getStatus());
                                } else {
                                    newOwner.setRedPacketStatus(RedPacketStatusEnum.OVERDUE.getStatus());
                                }

                                newOwner.setEffectiveStartTime(lastOwner.getEffectiveStartTime());
                                newOwner.setEffectiveEndTime(lastOwner.getEffectiveEndTime());

                                redPacketOwnerService.saveRedPacketOwner(newOwner);
                            }

                            redisUtil.delKeysLike(RedisKeys.RED_PACKET + lastOwner.getOwnUserId() + "*");
                            redisUtil.delKeysLike(RedisKeys.RED_PACKET_SHARE + lastOwner.getOwnUserId() + "*");
                        }
                    }
                }
            }
        } else if (RedPacketBackTypeEnum.PAID.getType() == request.getBackType()) {
            // 是否退还所有
            if (request.isBackAll()) {
                // todo nothing
            }
        }

        // 更新兔币状态为未使用状态
        redPacket.setId(redPacketOwner.getRedPacketId());
        redPacket.setStatus(RedPacketStatusEnum.NOT_USE.getStatus());
        redPacket.setUpdateTime(new Date());
        redPacket.setUsetime(null);

        redisUtil.delKeysLike(RedisKeys.RED_PACKET + redPacketOwner.getOwnUserId() + "*");

        redPacketService.updateRedPacketAll(redPacket);

        return true;
    }

    /*****
     * 兔币失效
     * @param userId:用户id
     */
    @Override
    @Transactional(propagation = Propagation.REQUIRED, rollbackFor = {Exception.class,
            RuntimeException.class})
    public void redPacketInvalid(int userId) {

        final String uuid = UUID.randomUUID().toString();

        logger.info("--------uuid==={} method redPacketInvalid  userId={}", uuid, userId);

        // 防刷控制
        String refreshKey = RedisKeys.RED_PACKET_REFRESH + "" + userId;

        String refreshValue = redisUtil.get(refreshKey);

        if (StringUtils.isNotBlank(refreshValue)) {
            // 上次刷新时间
            long lastRefreshTime = Long.valueOf(refreshValue);
            // 如果距离上次刷新时间小于等于 3  则不去刷新
            if (System.currentTimeMillis() - lastRefreshTime <= 3 * 1000) {
                logger.info("----uuid=={}--userId = {} ---上次刷新时间离本次刷新时间间隔小于3秒 不执行失效处理----", uuid,
                        userId);
                return;
            } else {
                redisUtil.set(refreshKey,
                        String.valueOf(System.currentTimeMillis() + new Random().nextInt(1000) + 2000), 5 * 60);
            }
        } else {
            redisUtil.set(refreshKey,
                    String.valueOf(System.currentTimeMillis() + new Random().nextInt(1000) + 2000), 5 * 60);
        }

        boolean acquireLock =
                redisUtil
                        .setnx(RedisKeys.RED_PACKET_INVALID_UPDATE_LOCK + userId, "1", 1 * 60)
                        > 0;

        if (!acquireLock) {
            logger.info("---uuid === {} --没有获取的失效更新红包锁--------userId = {}", uuid, userId);
            return;
        }
        logger.info("----uuid === {} ---------开始执行红包失效退回处理------ userId = {}------", uuid, userId);

        List<RedPacketOwner> ownerList = redPacketOwnerService.listWillInvalidRedPacketByUserId(userId);

        if (CollectionUtils.isEmpty(ownerList)) {
            logger.info("-----uuid === {} ---------没有要处理的数据------ userId = {}------", uuid, userId);
            return;
        }

        long startTime = System.currentTimeMillis();

        // 拥有者更新的集合
        List<RedPacketOwner> updateRedPacketList = new ArrayList<RedPacketOwner>();
        // 拥有者新增的集合
        List<RedPacketOwner> insertRedPacketList = new ArrayList<RedPacketOwner>();
        // 分享记录更新的集合
        List<RedPacketShareHist> updateShareHistList = new ArrayList<RedPacketShareHist>();

        ownerList.stream().forEach(owner -> {

            RedPacketOwner newOwner = new RedPacketOwner();
            newOwner.setTitle(owner.getTitle());
            newOwner.setOwnUserId(owner.getOwnUserId());
            newOwner.setRedPacketId(owner.getRedPacketId());
            newOwner.setRedPacketShareHistId(0);
            newOwner.setLastOwnerId(0);
            newOwner.setAllowShare(true);
            newOwner.setOwnTime(new Date());
            newOwner.setSendUserId(0);
            newOwner.setOwnStatus((short) 1); // 拥有状态：0：曾经；1：拥有
            newOwner.setGiftType(owner.getGiftType());
            newOwner.setRedPacketShareStatus(RedPacketShareStatusEnum.NOT_SHARE.getStatus());
            newOwner.setRedPacketStatus(RedPacketStatusEnum.NOT_USE.getStatus());
            newOwner.setEffectiveStartTime(owner.getEffectiveStartTime());
            newOwner.setEffectiveEndTime(owner.getEffectiveEndTime());

            // 未分享
            if (owner.getRedPacketShareStatus() == RedPacketShareStatusEnum.NOT_SHARE.getStatus()) {
                if (owner.getEffectiveEndTime().getTime() < System.currentTimeMillis()) {
                    RedPacketOwner updateOwner = new RedPacketOwner();
                    updateOwner.setId(owner.getId());
                    updateOwner.setOwnUserId(owner.getOwnUserId());
                    updateOwner.setRedPacketShareStatus(RedPacketShareStatusEnum.NOT_SHARE.getStatus());
                    updateOwner.setRedPacketStatus(RedPacketStatusEnum.OVERDUE.getStatus());
                    updateRedPacketList.add(updateOwner);
                }
            } else if (owner.getRedPacketShareStatus() == RedPacketShareStatusEnum.SHARED.getStatus()) {
                // 1、兔币使用失效
                if (owner.getEffectiveEndTime().getTime() < System.currentTimeMillis()) {
                    // 有分享记录
                    if (owner.getRedPacketShareHistId() > 0) {
                        RedPacketShareHist hist = redPacketShareHistService
                                .getRedPacketShareHistById(owner.getRedPacketShareHistId());
                        if (hist != null) {
                            // 在未领取（永久分享跟限时分享）或 限时分享已领取的情况下都退回
                            if ((hist.getStatus() == RedPacketShareHistStatusEnum.NOT_RECEIVE.getStatus())) {

                                newOwner.setTitle("分享退回兔币");
                                newOwner.setOwnUserId(owner.getOwnUserId());
                                newOwner.setGiftType(RedPacketGiftTypeEnum.SHARE_BACK.getType());
                                newOwner.setRedPacketShareStatus(RedPacketShareStatusEnum.NOT_SHARE.getStatus());
                                newOwner.setRedPacketStatus(RedPacketStatusEnum.OVERDUE.getStatus());
                                newOwner.setEffectiveStartTime(owner.getEffectiveStartTime());
                                newOwner.setEffectiveEndTime(owner.getEffectiveEndTime());
                                insertRedPacketList.add(newOwner);

                                RedPacketOwner updateOwner = new RedPacketOwner();
                                updateOwner.setOwnUserId(owner.getOwnUserId());
                                updateOwner.setId(owner.getId());
                                updateOwner.setOwnStatus(RedPacketOwnStatusEnum.IN_THE_PAST.getStatus());
                                updateOwner.setReturnTime(new Date());
                                updateRedPacketList.add(updateOwner);

                                RedPacketShareHist updateHist = new RedPacketShareHist();
                                updateHist.setUpdateTime(new Date());
                                updateHist.setReturnTime(new Date());
                                updateHist.setStatus(RedPacketShareHistStatusEnum.BACKED.getStatus());
                                updateHist.setId(hist.getId());
                                updateHist.setShareUserId(hist.getShareUserId());
                                updateShareHistList.add(updateHist);
                            }
                        }
                    }
                }
                // 兔币分享失效 , 兔币使用未失效
                else if (owner.getShareFailureTime() != null
                        && owner.getShareFailureTime().getTime() < System.currentTimeMillis()
                        && owner.getEffectiveEndTime().getTime() > System.currentTimeMillis()) {

                    if (owner.getRedPacketShareHistId() > 0) {
                        RedPacketShareHist hist = redPacketShareHistService
                                .getRedPacketShareHistById(owner.getRedPacketShareHistId());
                        if (hist != null) {
                            // 如果永久分享跟限时分享在未领取的状态下都退回给分享人 或者  如果是限时分享 已领取未使用的状态下退回给分享人
                            if ((hist.getStatus() == RedPacketShareHistStatusEnum.NOT_RECEIVE.getStatus())) {
                                newOwner.setTitle("分享退回兔币");
                                newOwner.setOwnUserId(owner.getOwnUserId());
                                newOwner.setGiftType(RedPacketGiftTypeEnum.SHARE_BACK.getType());
                                newOwner.setRedPacketShareStatus(RedPacketShareStatusEnum.NOT_SHARE.getStatus());
                                newOwner.setRedPacketStatus(RedPacketStatusEnum.NOT_USE.getStatus());
                                newOwner.setEffectiveStartTime(owner.getEffectiveStartTime());
                                newOwner.setEffectiveEndTime(owner.getEffectiveEndTime());
                                insertRedPacketList.add(newOwner);

                                RedPacketOwner updateOwner = new RedPacketOwner();
                                updateOwner.setOwnUserId(owner.getOwnUserId());
                                updateOwner.setId(owner.getId());
                                updateOwner.setReturnTime(new Date());
                                updateOwner.setOwnStatus(RedPacketOwnStatusEnum.IN_THE_PAST.getStatus());
                                updateRedPacketList.add(updateOwner);

                                RedPacketShareHist updateHist = new RedPacketShareHist();
                                updateHist.setReturnTime(new Date());
                                updateHist.setUpdateTime(new Date());
                                updateHist.setStatus(RedPacketShareHistStatusEnum.BACKED.getStatus());
                                updateHist.setId(hist.getId());
                                updateHist.setShareUserId(hist.getShareUserId());
                                updateShareHistList.add(updateHist);
                            }
                        }
                    }
                }


                if (owner.getRedPacketShareHistId() > 0) {
                    RedPacketShareHist hist = redPacketShareHistService
                            .getRedPacketShareHistById(owner.getRedPacketShareHistId());
                    if (hist != null) {
                        // 如果红包已领取或已使用。领取人的使用有效期过期，则返回给分享者
                        if ((hist.getStatus() == RedPacketShareHistStatusEnum.RECEIVED.getStatus())
                                || (hist.getStatus() == RedPacketShareHistStatusEnum.USED.getStatus())) {

                            RedPacketOwner nextOwner = redPacketOwnerService.getRedPacketOwner(userId, (short) 0, owner.getId());

                            if (nextOwner != null) {

                                if (nextOwner.getEffectiveEndTime().getTime() < System.currentTimeMillis()) {
                                    newOwner.setTitle("分享退回兔币");
                                    newOwner.setOwnUserId(owner.getOwnUserId());
                                    newOwner.setGiftType(RedPacketGiftTypeEnum.SHARE_BACK.getType());
                                    // 如果上级分享使用时间有效 状态为未使用
                                    if (owner.getEffectiveEndTime().getTime() > System.currentTimeMillis()) {
                                        newOwner.setRedPacketStatus(RedPacketStatusEnum.NOT_USE.getStatus());
                                    } else {
                                        newOwner.setRedPacketStatus(RedPacketStatusEnum.OVERDUE.getStatus());
                                    }

                                    newOwner.setEffectiveStartTime(owner.getEffectiveStartTime());
                                    newOwner.setEffectiveEndTime(owner.getEffectiveEndTime());
                                    insertRedPacketList.add(newOwner);

                                    RedPacketOwner updateOwner = new RedPacketOwner();
                                    updateOwner.setId(owner.getId());
                                    updateOwner.setOwnUserId(owner.getOwnUserId());
                                    updateOwner.setReturnTime(new Date());
                                    updateOwner.setOwnStatus(RedPacketOwnStatusEnum.IN_THE_PAST.getStatus());
                                    updateRedPacketList.add(updateOwner);

                                    RedPacketShareHist updateHist = new RedPacketShareHist();
                                    updateHist.setId(hist.getId());
                                    updateHist.setShareUserId(hist.getShareUserId());
                                    updateHist.setStatus(RedPacketShareHistStatusEnum.BACKED.getStatus());
                                    updateHist.setReturnTime(new Date());
                                    updateHist.setUpdateTime(new Date());
                                    updateShareHistList.add(updateHist);

                                }

                            }
                        }
                    }
                }
            }

        });

        if (!CollectionUtils.isEmpty(insertRedPacketList)) {
            redPacketOwnerService.batchSaveRedPacketOwner(insertRedPacketList);
            insertRedPacketList.stream().forEach(insertOwner -> {
                redisUtil.delKeysLike(RedisKeys.RED_PACKET + insertOwner.getOwnUserId() + "*");
                redisUtil.delKeysLike(RedisKeys.RED_PACKET_SHARE + insertOwner.getOwnUserId() + "*");
            });
        }

        if (!CollectionUtils.isEmpty(updateRedPacketList)) {
            updateRedPacketList.stream()
                    .forEach(updateOwner -> {
                        redPacketOwnerService.updateRedPacketOwner(updateOwner);
                        redisUtil.delKeysLike(RedisKeys.RED_PACKET + updateOwner.getOwnUserId() + "*");
                        redisUtil.delKeysLike(RedisKeys.RED_PACKET_SHARE + updateOwner.getOwnUserId() + "*");
                    });
        }

        if (!CollectionUtils.isEmpty(updateShareHistList)) {
            updateShareHistList.stream().forEach(
                    updateShareHist -> {
                        redPacketShareHistService.updateRedPacketShareHist(updateShareHist);
                        redisUtil.delKeysLike(RedisKeys.RED_PACKET + updateShareHist.getShareUserId() + "*");
                        redisUtil
                                .delKeysLike(RedisKeys.RED_PACKET_SHARE + updateShareHist.getShareUserId() + "*");
                    });
        }

        // 删除缓存
        redisUtil.delKeysLike(RedisKeys.RED_PACKET + userId + "*");
        redisUtil.delKeysLike(RedisKeys.RED_PACKET_SHARE + userId + "*");
        // 删除锁
        redisUtil.del(RedisKeys.RED_PACKET_INVALID_UPDATE_LOCK + userId);

        long endTime = System.currentTimeMillis();

        logger.info("-----uuid === {} ---总共处理用时 = {} 毫秒 ------ userId = {}------", uuid,
                (endTime - startTime), userId);
    }

    /****
     * 通过事件类型给用户发兔币
     *
     * @param request
     * @return
     */
    @Override
    @Transactional(propagation = Propagation.REQUIRED, rollbackFor = {Exception.class,
            RuntimeException.class})
    public boolean giveRedPacketByEventType(GiveRedPacketByEventRequest request)
            throws RedPacketBizException {

        logger.info("==== method giveRedPacketByEventType request={}", request);

        if (request == null) {
            logger.error("==add redpackage -- param is null");
            return false;
        }

        if (request.getReceiveUserId() <= 0) {
            logger.error("==add redpackage --  兔币领取人不能为空。receiveUserId = {}", request.getReceiveUserId());
            return false;
        }

        RedPacketEventTypeEnum typeEnum = RedPacketEventTypeEnum.getByType(request.getEventType());

        if (typeEnum == null) {
            logger.error("==add redpackage --  传入事件类型不存在。eventType = {}", request.getEventType());
            return false;
        }

        int giveType;

        if (typeEnum.getType().equals(RedPacketEventTypeEnum.INVITING_FIRST_ORDER.getType())) {
            giveType = RedPacketGiftTypeEnum.REGISTER_NEW.getType();
            if (request.getInvitationUserId() <= 0) {
                logger.error("add redpackage --  ==邀请人不能为空。 invitationUserId= {}", request.getInvitationUserId());
                return false;
            }
        } else if (typeEnum.getType().equals(RedPacketEventTypeEnum.NEW_STORE_OWNER_AWARD.getType())) {
            giveType = RedPacketGiftTypeEnum.OPEN_STORE.getType();
        } else {
            giveType = RedPacketGiftTypeEnum.SYSTEM_TYPE.getType();
        }

        RedPacketRecord redPacketRecord = redPacketRecordService
                .getRedPacketRecordByEventType(typeEnum.getType());

        if (redPacketRecord == null) {
            logger.error("==add redpackage --  免币发行记录不存在。eventType = {}", typeEnum.getType());
            return false;
        }

        if (redPacketRecord.getStartTime().getTime() > System.currentTimeMillis()
                || redPacketRecord.getEndTime().getTime() < System.currentTimeMillis()) {
            logger.error("==add redpackage --  兔币发行记录不在有效时间范围。startTime = {},endTime ={}", redPacketRecord.getStartTime(),
                    redPacketRecord.getEndTime());
            return false;
        }

        User user = userService.getUserById((long) request.getReceiveUserId());

        if (user == null) {
            logger.error("==add redpackage --  领取人信息不存在。 receiveUserId= {}", request.getReceiveUserId());
            return false;
        }

        // 查询发行记录关联表
        List<RedPacketRecordOmtRl> recordOmtRls = redPacketRecordOmtRlService
                .listByRedPacketRecordId(redPacketRecord.getId());
        if (CollectionUtils.isEmpty(recordOmtRls)) {
            logger.error("==add redpackage --  兔币发行记录没有关联兔币模板");
            return false;
        }

        List<Integer> omtIdList = recordOmtRls.stream().filter(redPacketRecordOmtRl -> {
            if (redPacketRecordOmtRl.getRemainCount() <= 0) {
                logger.error("add redpackage --  ==兔币发行记录的兔币数量不够。rlId =", redPacketRecordOmtRl.getId());
                return false;
            }
            if (redPacketRecordOmtRl.getSendNums() <= 0) {
                logger.error("==add redpackage --  兔币发行记录的兔币发送数量不能小于0。rlId = {}", redPacketRecordOmtRl.getId());
                return false;
            }
            return true;
        }).map(RedPacketRecordOmtRl::getRedPacketOmtId).collect(Collectors.toList());

        if (CollectionUtils.isEmpty(omtIdList)) {
            logger.error("==add redpackage --  没有找到有效的兔币模块。redPacketRecordId = {}", redPacketRecord.getId());
            return false;
        }
        // 查询兔币模块列表
        List<RedPacketOmt> redPacketOmtList = redPacketOmtService.listByIds(omtIdList);

        if (CollectionUtils.isEmpty(redPacketOmtList)) {
            logger.error("==add redpackage --  兔币发行记录没有关联任何兔币模板");
            return false;
        }

        Map<Integer, RedPacketOmt> redPacketOmtMap = redPacketOmtList.stream().filter(redPacketOmt -> {
            if (redPacketOmt.getRedPacketAgingType().intValue() == 0 && (
                    redPacketOmt.getRedPacketStartTime().getTime() > System.currentTimeMillis() ||
                    redPacketOmt.getRedPacketEndTime().getTime() < System.currentTimeMillis())) {
                throw new RedPacketBizException("==add redpackage --兔币模板有效时间范围无效。开始时间=" + DateUtil.toDateStr(redPacketOmt.getRedPacketStartTime()) + ",结束时间=" + DateUtil.toDateStr(redPacketOmt.getRedPacketEndTime()));
            }
            return true;
        }).collect(Collectors.toMap(RedPacketOmt::getId, omt -> omt));

        RedPacketOwner owner = new RedPacketOwner();

        owner.setGiftType((short) giveType);

        owner.setSendUserId(request.getInvitationUserId());

        final long[] sum = {0};

        recordOmtRls.stream().forEach(rl -> {

            RedPacketOmt redPacketOmt = redPacketOmtMap.get(rl.getRedPacketOmtId());

            if (redPacketOmt != null) {
                IntStream.range(0, rl.getSendNums()).forEach(i -> {
                    RedPacket redPacket = new RedPacket();
                    redPacket.setStatus(RedPacketStatusEnum.NOT_USE.getStatus());
                    redPacket.setAmount(redPacketOmt.getRedPacketAmount());
                    redPacket.setRedPacketOmtId(redPacketOmt.getId());
                    redPacket.setRedPacketRecordId(rl.getRedPacketRecordId());
                    redPacket.setCode(RedPacketUtil.generateRedPacketCode(
                            RedPacketEventTypeEnum.getByType(redPacketRecord.getEventType()).getPrefix() + "-"
                                    + redPacketRecord.getId() + "-" + redPacketOmt.getId() + "-" + request.getReceiveUserId()));
                    redPacket.setTitle(redPacketOmt.getRedPacketTitle());
                    redPacket.setSubtitle(redPacketOmt.getRedPacketSubtitle());
                    redPacket.setCreateTime(new Date());
                    redPacket.setUpdateTime(new Date());
                    redPacket.setRedPacketType((short) 0);
                    redPacket.setAllowShare(redPacketOmt.getRedPacketAllowShare());
                    redPacket.setAllowRefundReturn(redPacketOmt.getRedPacketAllowRefundReturn());

                    // 0==固定时间,1==动态时间
                    if (redPacketOmt.getRedPacketAgingType().intValue() == 0) {
                        if (redPacketOmt.getRedPacketStartTime().getTime() < System.currentTimeMillis()
                                && redPacketOmt.getRedPacketEndTime().getTime() > System.currentTimeMillis()) {
                            redPacket.setStartTime(redPacketOmt.getRedPacketStartTime());
                            redPacket.setEndTime(redPacketOmt.getRedPacketEndTime());
                        }
                    } else {
                        Calendar calendar = Calendar.getInstance();
                        calendar.setTime(new Date());
                        calendar.add(Calendar.HOUR_OF_DAY, redPacketOmt.getRedPacketHourage().intValue());
                        redPacket.setStartTime(new Date());
                        redPacket.setEndTime(calendar.getTime());
                    }
                    //  更新兔币剩余数量
                    RedPacketRecordOmtRl updateOmtRl = new RedPacketRecordOmtRl();
                    updateOmtRl.setId(rl.getId());
                    updateOmtRl.setRemainCount(1);

                    boolean updateFlag = redPacketRecordOmtRlService.updateRedPacketRemainCount(updateOmtRl);

                    if (!updateFlag) {
                        throw new RedPacketBizException("兔币发行记录的剩余兔币数量不够");
                    }
                    //  插入兔币
                    redPacketService.saveRedPacket(redPacket);

                    owner.setTitle(redPacketRecord.getTitle());
                    owner.setOwnUserId(request.getReceiveUserId());
                    owner.setRedPacketId(redPacket.getId());
                    owner.setRedPacketShareHistId(0);
                    owner.setLastOwnerId(0);
                    owner.setAllowShare(redPacket.getAllowShare());
                    owner.setOwnTime(request.getCreateTime() == null ? new Date() : request.getCreateTime());
                    owner.setOwnStatus(RedPacketOwnStatusEnum.CURRENT.getStatus());
                    owner.setRedPacketShareStatus(RedPacketShareStatusEnum.NOT_SHARE.getStatus());
                    owner.setRedPacketStatus(RedPacketStatusEnum.NOT_USE.getStatus());
                    owner.setEffectiveStartTime(redPacket.getStartTime());
                    owner.setEffectiveEndTime(redPacket.getEndTime());
                    redPacketOwnerService.saveRedPacketOwner(owner);
                    // 统计兔币金额
                    sum[0] = sum[0] + redPacketOmt.getRedPacketAmount().longValue();

                });
            }
        });
        // 只有直播间分享才发送短信通知
        if (typeEnum.getType().equals(RedPacketEventTypeEnum.LIVE_SHARE_AWARD.getType())) {
            if (sum[0] > 0 && request.getReceiveUserId() > 0) {
                BaseRestrictions baseRestrictions = baseRestrictionsService
                        .getBaseRestrictionsForCache(LIVE_ROOM_GIVE_REDPACKET);
                if (baseRestrictions == null || StringUtils.isBlank(baseRestrictions.getName())) {
                    logger.error("直播间发红包短信通知模板没有配置。type={}", LIVE_ROOM_GIVE_REDPACKET);
                } else {
                    String msg = MessageFormat.format(baseRestrictions.getName(), BigDecimal.valueOf(sum[0]).divide(BigDecimal.valueOf(100)).toString());
                    logger.info("直播间发红包短信通知。userName={},msg={}", user.getUserName(), msg);
                    try {
                        smsService.sendMsgJianZhou(true, user.getUserName(), msg);
                    } catch (Exception e) {
                        logger.error("直播间发红包短信通知异常。userName={},msg={}", user.getUserName(), msg, e);
                    }
                }

            }
        }

        redisUtil.delKeysLike(RedisKeys.RED_PACKET + request.getReceiveUserId() + "*");

        return true;
    }

    /***
     * 根据shareKey获取兔币信息
     * @param request
     * @return
     */
    @Override
    public GetRedPacketByShareKeyVo getRedPacketByShareKey(GetRedPacketByShareKeyRequest request) {

        // 0：立即领取  1：已失效（他人已领取）  2：已领取（自己领取）  4：兔币过期（兔币使用过期或分享领取过期）  10：自己分享的兔币
        GetRedPacketByShareKeyVo vo = new GetRedPacketByShareKeyVo();
        vo.setStatus(0);

        if (StringUtils.isBlank(request.getShareKey())) {
            throw new RedPacketBizException("请求参数不能为空");
        }

        // 是否已过期
        String jsonValue = redisUtil
                .get(RedisKeys.RED_PACKET_SHARE_STATUS + "overdue_" + request.getShareKey());

        if (StringUtils.isNotBlank(jsonValue)) {
            return JSON.parseObject(jsonValue, GetRedPacketByShareKeyVo.class);
        }

        if (request.getUserId() > 0) {
            // 是否是自己分享
            jsonValue = redisUtil
                    .get(RedisKeys.RED_PACKET_SHARE_STATUS + "myself_" + request.getShareKey() + "_" + request
                            .getUserId());

            if (StringUtils.isNotBlank(jsonValue)) {
                return JSON.parseObject(jsonValue, GetRedPacketByShareKeyVo.class);
            }
            // 是否是自己领取
            jsonValue = redisUtil.get(
                    RedisKeys.RED_PACKET_SHARE_STATUS + "receive_" + request.getShareKey() + "_" + request
                            .getUserId());

            if (StringUtils.isNotBlank(jsonValue)) {
                return JSON.parseObject(jsonValue, GetRedPacketByShareKeyVo.class);
            }

            // 是否已失效
            jsonValue = redisUtil
                    .get(RedisKeys.RED_PACKET_SHARE_STATUS + "invalid_" + request.getShareKey());

            if (StringUtils.isNotBlank(jsonValue)) {
                return JSON.parseObject(jsonValue, GetRedPacketByShareKeyVo.class);
            }
        }

        String shareKey = RedisKeys.RED_PACKET_SHARE_KEY + request.getShareKey();

        String shareValue = redisUtil.get(shareKey);

        RedPacketShareHist redPacketShareHist = null;

        if (StringUtils.isBlank(shareValue)) {
            redPacketShareHist = redPacketShareHistService
                    .getRedPacketShareHisByShareUrl(request.getShareKey());
        } else {
            redPacketShareHist = redPacketShareHistService
                    .getRedPacketShareHistById(Integer.valueOf(shareValue));
        }
        if (redPacketShareHist == null) {
            throw new RedPacketBizException("兔币分享记录不存在");
        }

        RedPacket redPacket = redPacketService.getRedPacketById(redPacketShareHist.getRedPacketId());
        if (redPacket == null) {
            throw new RedPacketBizException("兔币记录不存在");
        }

        User shareUser = userService.getUserById(Long.valueOf(redPacketShareHist.getShareUserId()));
        if (shareUser == null) {
            throw new RedPacketBizException("兔币分享人信息不存在");
        }

        RedPacketOwner redPacketOwner = redPacketOwnerService
                .getByRedPacketShareHistId(redPacketShareHist.getId());

        if (redPacketOwner == null) {
            throw new RedPacketBizException("兔币拥有记录不存在");
        }
        // 判断 兔币使用时间是否已过期 或者 兔币领取时间是否已失效
        if ((redPacketOwner.getEffectiveEndTime().getTime() < System.currentTimeMillis())
                || (redPacketOwner.getShareFailureTime() != null &&
                redPacketOwner.getShareFailureTime().getTime() < System.currentTimeMillis())) {
            vo.setStatus(4);
        }
        vo.setLastValidTime(
                new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(redPacketOwner.getEffectiveEndTime()));
        vo.setShareUserName(shareUser.getNickName());
        vo.setShareUserPic(this.getImageAllPath(shareUser.getPicture()));
        vo.setAmount(BigDecimal.valueOf(redPacket.getAmount().longValue()).divide(BigDecimal.valueOf(100)).toString());

        // 已过期
        if (vo.getStatus() == 4) {
            redisUtil
                    .set(RedisKeys.RED_PACKET_SHARE_STATUS + "overdue_" + request.getShareKey(),
                            JSON.toJSONString(vo),
                            2 * 24 * 60 * 60);
            return vo;
        }

        if (request.getUserId() > 0 && redPacketShareHist.getShareUserId().intValue() == request
                .getUserId()) {
            // 不能领取自己的兔币
            vo.setStatus(10);
        } else {
            if (redPacketShareHist.getStatus() == RedPacketShareHistStatusEnum.RECEIVED.getStatus()) {
                // 自己已领取
                if (request.getUserId() > 0 && redPacketShareHist.getReceiveUserId().intValue() == request
                        .getUserId()) {
                    vo.setStatus(2);
                } else {
                    // 失效（他人领取）
                    vo.setStatus(1);
                }
            } else if (redPacketShareHist.getStatus() != RedPacketShareHistStatusEnum.NOT_RECEIVE
                    .getStatus()) {
                // 失效（他人领取）
                vo.setStatus(1);
            }
        }

        if (vo.getStatus() == 10) {
            redisUtil
                    .set(RedisKeys.RED_PACKET_SHARE_STATUS + "myself_" + request.getShareKey() + "_" + request
                                    .getUserId()
                            , JSON.toJSONString(vo), 2 * 24 * 60 * 60);
            return vo;
        }
        // 自己领取
        if (vo.getStatus() == 2) {
            redisUtil
                    .set(
                            RedisKeys.RED_PACKET_SHARE_STATUS + "receive_" + request.getShareKey() + "_" + request
                                    .getUserId()
                            , JSON.toJSONString(vo), 2 * 60);
            return vo;
        }

        // 已失效
        if (vo.getStatus() == 1) {
            redisUtil.set(RedisKeys.RED_PACKET_SHARE_STATUS + "invalid_" + request.getShareKey(),
                    JSON.toJSONString(vo), 2 * 60);
            return vo;
        }

        return vo;
    }

    @Override
    public PerRedPacketResponseVo showRedPacketList(Long userId, int type, int startIndex,
                                                    Integer pageSize,
                                                    String clientType) throws IOException {

        //this.limitRedPacketRefreshRate(userId);
        // 红包失效处理
        this.redPacketInvalid(userId.intValue());

        List<PerRedPacketVo> list = new ArrayList<>();
        PerRedPacketResponseVo redPacketResVo = new PerRedPacketResponseVo();
        BigDecimal ioo = new BigDecimal(10000);
        List<PerRedPacketVo> subList = new ArrayList<>();
        String key = RedisKeys.RED_PACKET + userId + RedisKeys.RPTYPE + type;
        if (!StringUtils.isEmpty(redisUtil.get(key))) {
            PerRedPacketResponseVo obj = JSON
                    .parseObject(redisUtil.get(key), PerRedPacketResponseVo.class);
            //redis 中的价格已经去掉两个0 补齐
            if (null != obj.getTotalAmount()) {
                obj.setTotalAmount(obj.getTotalAmount().multiply(ioo).setScale(0));
            }
            List<PerRedPacketVo> redPacketList = obj.getRedPacketList();
            for (PerRedPacketVo perRedPacketVo : redPacketList) {
                if (null != perRedPacketVo.getAmount()) {
                    perRedPacketVo.setAmount(perRedPacketVo.getAmount().multiply(ioo).setScale(0));
                }
            }
            //在区间内
            //在区间中
            //起始值小于 集合  起始值+偏移 > 集合
            if (startIndex <= obj.getRedPacketList().size() && startIndex + pageSize >= obj
                    .getRedPacketList().size()) {
                subList = obj.getRedPacketList().subList(startIndex, obj.getRedPacketList().size());
            } else if (startIndex > obj.getRedPacketList().size()) {

            } else {
                subList = obj.getRedPacketList().subList(startIndex, startIndex + pageSize);
            }

            obj.setRedPacketList(subList);
            return obj;
        }

        // 未使用的所有兔币面值加起来总和
        BigDecimal totalAmount = redPacketService.queryTotalRedPacketByUserId(userId);
        int totalSize = redPacketOwnerService.queryRedPacketSize(userId, type);
        redPacketResVo.setTotal(totalSize);
        redPacketResVo.setTotalAmount(totalAmount);

        list = redPacketOwnerService.showRedPacketList(userId, type, startIndex, pageSize, clientType);
        redPacketResVo.setRedPacketList(list);
        if (null != list && list.size() != 0) {
            //redPacketResVo.setRedPacketList(list);
            if (type == 0) {   //兔币未使用  需要校验 是否 有值  有值 存redis
                if (redPacketResVo.getTotal() != 0 && new BigDecimal(0) != redPacketResVo
                        .getTotalAmount()) {
                    redisUtil.set(key, JsonUtil.toJson(redPacketResVo), 300000);
                }
            } else {  // 出未使用  状态
                redisUtil.set(key, JsonUtil.toJson(redPacketResVo), 300000);
            }
            if (startIndex <= list.size() && startIndex + pageSize >= list.size()) {
                subList = list.subList(startIndex, list.size());
            } else if (startIndex > list.size()) {

            } else {
                subList = list.subList(startIndex, startIndex + pageSize);
            }

            redPacketResVo.setRedPacketList(subList);
        }
        return redPacketResVo;
    }

    /*****
     * 根据兔币板块发送兔币
     * @param request
     * @return
     * @throws RedPacketBizException
     */
    @Override
    public boolean giveRedPacketByTemplate(GiveRedPacketByTemplateRequest request)
            throws RedPacketBizException {

        logger.info("===method giveRedPacketByTemplate request={}", request);
        Assert.notNull(request, "传入参数不能为空");

        if (CollectionUtils.isEmpty(request.getUserIdList())) {
            throw new RedPacketBizException("赠送的用户ID集合不能为空!");
        }

        // 用户列表长度
        int userSize =
                CollectionUtils.isEmpty(request.getUserIdList()) ? 0 : request.getUserIdList().size();
        if (userSize == 0) {
            logger.error("==用户列表长度为0.");
            throw RedPacketBizException.PARAM_ERROR;
        }
        // 最大用户个数
        int maxLimitSize = 100;

        logger.info("==============本次userSize == {} -------------------------------", userSize);

        if (userSize > maxLimitSize) {
            logger.error("==用户列表长度为{},已大于最大限制个{}。id = {}", userSize, maxLimitSize);
            throw RedPacketBizException.PARAM_ERROR;
        }
        // 查询兔币模块列表
        List<RedPacketOmt> redPacketOmtList = redPacketOmtService
                .listByIds(Arrays.asList(request.getTemplateId()));

        if (CollectionUtils.isEmpty(redPacketOmtList)) {
            throw new RedPacketBizException("没有任何兔币模板");
        }

        List<RedPacketOmt> filterOmtList = redPacketOmtList.stream().filter(redPacketOmt -> {
            if (redPacketOmt.getRedPacketAgingType().intValue() == 0) {
                if (redPacketOmt.getRedPacketEndTime().getTime() < System.currentTimeMillis()) {
                    throw new RedPacketBizException("兔币模板有效时间范围无效");
                }
            }
            return true;
        }).collect(Collectors.toList());

        // 用户id列表
        List<Integer> userIdList = request.getUserIdList();

        filterOmtList.stream().forEach(omt -> {
            // 生成userSize个兔币
            List<RedPacket> redPacketList = this.generateRedPacket(userSize, userIdList, omt, "NO-0-" + omt.getId());

            RedPacketOmt updateOmt = new RedPacketOmt();
            updateOmt.setId(omt.getId());
            updateOmt.setRemainCount(userSize);
            // 更新兔币模块剩余数量
            boolean flag = redPacketOmtService.updateRedPacketOmtRemainCount(updateOmt);
            if (!flag) {
                throw new RedPacketBizException("兔币模板剩余数量不够");
            }
            //  批量插入兔币
            redPacketService.batchSaveRedPacket(redPacketList);

            List<RedPacketOwner> ownerList = this.generateOwnerList(userIdList, redPacketList);
            //  批量将兔币关联用户
            redPacketOwnerService.batchSaveRedPacketOwner(ownerList);
        });

        userIdList.stream()
                .forEach(userId -> redisUtil.delKeysLike(RedisKeys.RED_PACKET + userId + "*"));

        return true;
    }

    private List<RedPacket> generateRedPacket(final int userSize, final List<Integer> userIdList, final RedPacketOmt redPacketOmt,
                                              final String codePrefix) {
        List<RedPacket> redPacketList = new ArrayList<RedPacket>(userSize);
        IntStream.range(0, userSize).forEach(k -> {
            RedPacket redPacket = new RedPacket();
            redPacket.setAmount(redPacketOmt.getRedPacketAmount());
            redPacket.setRedPacketOmtId(redPacketOmt.getId());
            redPacket.setRedPacketRecordId(0);
            redPacket.setCode(RedPacketUtil.generateRedPacketCode(codePrefix + "-" + userIdList.get(k)));
            redPacket.setTitle(redPacketOmt.getRedPacketTitle());
            redPacket.setSubtitle(redPacketOmt.getRedPacketSubtitle());
            redPacket.setCreateTime(new Date());
            redPacket.setUpdateTime(new Date());
            redPacket.setStatus(RedPacketStatusEnum.NOT_USE.getStatus());
            redPacket.setRedPacketType((short) 0);
            redPacket.setAllowShare(redPacketOmt.getRedPacketAllowShare());
            redPacket.setAllowRefundReturn(redPacketOmt.getRedPacketAllowRefundReturn());
            // 0==固定时间,1==动态时间
            if (redPacketOmt.getRedPacketAgingType().intValue() == 0) {
                redPacket.setStartTime(redPacketOmt.getRedPacketStartTime());
                redPacket.setEndTime(redPacketOmt.getRedPacketEndTime());
                redPacketList.add(redPacket);
            } else {
                Calendar calendar = Calendar.getInstance();
                calendar.setTime(new Date());
                calendar.add(Calendar.HOUR_OF_DAY, redPacketOmt.getRedPacketHourage().intValue());
                redPacket.setStartTime(new Date());
                redPacket.setEndTime(calendar.getTime());
                redPacketList.add(redPacket);
            }
        });
        return redPacketList;
    }

    private List<RedPacketOwner> generateOwnerList(final List<Integer> userIdList,
                                                   final List<RedPacket> redPackets) {
        int userSize = userIdList.size();
        List<RedPacketOwner> ownerList = new ArrayList<RedPacketOwner>(userSize);
        IntStream.range(0, userSize).forEach(index -> {
            RedPacket redPacket = redPackets.get(index);
            RedPacketOwner owner = new RedPacketOwner();
            owner.setTitle(redPacket.getTitle());
            owner.setOwnUserId(userIdList.get(index));
            owner.setRedPacketId(redPacket.getId());
            owner.setRedPacketShareHistId(0);
            owner.setLastOwnerId(0);
            owner.setAllowShare(redPacket.getAllowShare());
            owner.setOwnTime(new Date());
            owner.setSendUserId(0);
            owner.setOwnStatus(RedPacketOwnStatusEnum.CURRENT.getStatus());
            owner.setGiftType(RedPacketGiftTypeEnum.SYSTEM_TYPE.getType());
            owner.setRedPacketShareStatus(RedPacketShareStatusEnum.NOT_SHARE.getStatus());
            owner.setRedPacketStatus(RedPacketStatusEnum.NOT_USE.getStatus());
            owner.setEffectiveStartTime(redPacket.getStartTime());
            owner.setEffectiveEndTime(redPacket.getEndTime());
            ownerList.add(owner);
        });
        return ownerList;
    }
}
